/** 
 * Filename: app_main.c
 * Description: enable timer3 as system clock. enable timer3 int.
 * flash led when timeout. use printf to send msg to uart.
 * Modification:
 * creation, hzheng, 2023.07.30
 * add printf, hzheng, 2023.07.31
 * add timer3 int, hzheng, 2023.08.10
 * add HalClockInit() to init timer3, when timeout call OsTickHandler; hzheng, 2023.08.12
 */

#include <stdio.h>

#include "los_task.h"

#include <stddef.h>

void mydelay(void);
void disableGlobalInt(void);
void enableGlobalInt(void);
void *memset(void *s, int c, size_t n);
/*+************************************************
 * HI3861 peripheral registers address definition
 ***********************************************-*/

/**
 * GPIO registers
 */
#define GPIO_ODR *((volatile unsigned int *)0x50006000)

/**
 * UART0 registers
 */
#define UART0_DR *((volatile unsigned int *)0x40008000)
#define UART0_FR *((volatile unsigned int *)0x40008018)
#define UART0_IBRD *((volatile unsigned int *)0x40008024)
#define UART0_FBRD *((volatile unsigned int *)0x40008028)
#define UART0_LCR_H *((volatile unsigned int *)0x4000802c)
#define UART0_CR *((volatile unsigned int *)0x40008030)

/**
 * timer registers
 */
#define TIMER0_CONTROLREG *((volatile unsigned int *)0x40050008)
#define TIMER0_LOADCOUNT *((volatile unsigned int *)0x40050000)
#define TIMER0_EOI *((volatile unsigned int *)0x4005000c)

#define TIMER2_CONTROLREG *((volatile unsigned int *)0x40050030)
#define TIMER2_LOADCOUNT *((volatile unsigned int *)0x40050028)
#define TIMER2_EOI *((volatile unsigned int *)0x40050034)

#define TIMER3_CONTROLREG *((volatile unsigned int *)0x40050044)
#define TIMER3_LOADCOUNT *((volatile unsigned int *)0x4005003c)
#define TIMER3_EOI *((volatile unsigned int *)0x40050048)

#define TIMERS_RAWINTSTATUS *((volatile unsigned int *)0x400500a8)
#define TIMERS_INTSTATUS *((volatile unsigned int *)0x400500a0)
#define TIMERS_EOI *((volatile unsigned int *)0x400500a4)


//init timer3 as system tick clock
#define TIMEOUT_PERIOD 8000000-1   //100ms while timer clk is 80MHz
void HalClockInit(void *handler, unsigned int max_ticks);



unsigned int gValue;
unsigned int gTaskID1;
TSK_INIT_PARAM_S gTask1;

//timer3 flag
unsigned int gTick;

//task1
static void TaskEntry1(void) {
  
  while (1)  {
    GPIO_ODR ^= 0x04; 
    LOS_Msleep(500);

  }
}


__attribute__((section(".text.my_main"))) void my_main() {
  unsigned int ret;
  memset((void *)&gTask1,0,sizeof(TSK_INIT_PARAM_S));
  
//  unsigned int i;
  GPIO_ODR = 0x04;   
  //
  //init uart0
  UART0_CR = 0;
//  UART0_LCR_H = 0x0060; //bit[6:5]=11
  UART0_LCR_H = 0x0070; //bit[6:5]=11, 8bits; bit4=1, enable fifo
  //baudrate=115200, 115200=fclk/(16*n)
  //fclk = 80M or 160M
  //n1=80M/16/115200=43.40278; 0.40278*64+0.5=26
  //n2=160M/16/115200=86.80556; 0.80556*64+0.5=52
  UART0_IBRD = 43;
  UART0_FBRD = 26;
  UART0_CR = 0x0301; //txen, rxen, uarten
//  UART0_DR = 0x41;

  printf("init LOS.\n");
  
  disableGlobalInt();
  
  //try ohos
  ret = LOS_KernelInit();
  if (ret != LOS_OK) {
    printf("LOS_KernelInit failed! ERROR: 0x%x\n", ret);
    GPIO_ODR = 0x00;  
    while(1) {
    }
  }
//  disableGlobalInt();
//  printf("after LOS_KernelInit.\n");
  
  //
  //start task 1
  gTask1.pfnTaskEntry = (TSK_ENTRY_FUNC)TaskEntry1;
  gTask1.uwStackSize  = 0x800;
  gTask1.pcName       = "TaskEntry1";
  gTask1.usTaskPrio   = 6;
//  printf("before LOS_TaskCreate.\n");
  ret = LOS_TaskCreate(&gTaskID1, &gTask1);
  if (ret != LOS_OK) {
    printf("Create Task failed! ERROR: 0x%x\n", ret);
    GPIO_ODR = 0x00;  
    while(1) {
    }
  }

//  printf("before LOS_Start.\n");
  
//  enableGlobalInt();
  
  //start LOS
  LOS_Start();

//should never reach here.
  while(1){

  }  
  
  
  
  /*
  //init timer3
  TIMER3_CONTROLREG &= ~(1<<0); //clear bit0, disable timer
  TIMER3_CONTROLREG |= 1<<1; //set bit1, period mode
  TIMER3_CONTROLREG &= ~(1<<2); //clear bit2, unmask interrupt means enable
  TIMER3_LOADCOUNT = TIMEOUT_PERIOD;
  TIMER3_CONTROLREG |= 1<<0; //set bit0, enable timer

  //enable timer3 interrupt
  //timer3 irqnum = systimer irqnum = 7, enable in vectors.s

  //set timer3 irq_priority 
  unsigned int csr_be0;  //int_prio

  __asm__ __volatile__("csrr %0, 0xbe0":"=r"(csr_be0));
  csr_be0 &= ~(0x0f<<8); //clear bit8-11
  csr_be0 |= 0x4<<8; //set bit8-11 prio to 4
  __asm__ __volatile__("csrw 0xbe0, %0":"=r"(csr_be0));
  
  */
  
  /*
  gTick = 0;
  //
  
  if ((gValue <0x30)||(gValue >0x39)) {
    gValue = 0x30;
  }
  
  while(1) {
    UART0_DR = gValue;
    gValue ++;
    mydelay();
   
    //check timeout
    if (gTick == 1) {
      printf("tick\n");
      gTick = 0;
    }
  }
  */
  
  
}

__attribute__((section(".text.my_main"))) void app_main() {
  printf("hello.\n");
  while(1) {
  }
}


__attribute__((section(".text.my_main"))) void mydelay(void) {
  unsigned int i;
  for (i=0;i<80000000;i++) {
    __asm__ __volatile__("nop");
  }
}

__attribute__((section(".text.my_main"))) void _putchar(char character) {
  //wait for tx fifo not full
  while (UART0_FR&(0x1<<5)) { //tx fifo full flag
    __asm__ __volatile__("nop");
  }
  UART0_DR = character;
/*
  unsigned int i;
  UART0_DR = character;
  
  for (i=0;i<80000;i++) {
    __asm__ __volatile__("nop");
  }
*/
}

/**
 * memcpy, memset
 * copy from https://blog.csdn.net/luobeihai/article/details/119711069
 */
void *memset(void *s, int c, size_t n) {
  char *xs = s;
  while(n--)
    *xs++ = c;
  return s;
}

void *memcpy(void *dest, const void *src, size_t n) {
  char *tmp = dest;
  const char *s = src;
  
  while (n--)
    *tmp++ =*s++;
  return dest;
}

/**
 * global isr
 */
void myisr(void) {
  volatile unsigned int i;
  volatile unsigned int mstatus;
  volatile unsigned int mcause;
  volatile unsigned int mepc;
  volatile unsigned int mtval;

//  __asm__ __volatile__("csrr %0, mstatus":"=r"(mstatus));
  __asm__ __volatile__("csrr %0, mcause":"=r"(mcause));
  
  printf("myisr: mcause=0x%x\n", mcause);
  
  //send mcause to uart
//  UART0_DR = mcause;

  if (mcause == 11) { //m ecall exception
    __asm__ __volatile__("csrr %0, mepc":"=r"(mepc));
    mepc = mepc + 4;
    __asm__ __volatile__("csrw mepc, %0":"=r"(mepc));
  }else if (mcause == 0x8000001c) { //timer 2 interrupt
    i = TIMER2_EOI; //clear int flag
    GPIO_ODR ^= 0x04;    
  }else if (mcause == 0x80000000 + 7) { //timer 3 interrupt
    i = TIMER3_EOI; //clear int flag
//    GPIO_ODR ^= 0x04;    
//    gTick = 1; //inform main loop
    OsTickHandler();
  }else {
    printf("mcause: 0x%x\n", mcause);
    __asm__ __volatile__("csrr %0, mtval":"=r"(mtval));
    printf("mtval: 0x%x, halt!\n", mtval);
    __asm__ __volatile__("csrr %0, mstatus":"=r"(mstatus));
    printf("mstatus: 0x%x\n", mstatus);
    while(1) {
    }
    
  }

}


//init timer3 as system tick clock
void HalClockInit(void *handler, unsigned int max_ticks) {
  printf("enter HalClockInit.\n");
  //init timer3
  TIMER3_CONTROLREG &= ~(1<<0); //clear bit0, disable timer
  TIMER3_CONTROLREG |= 1<<1; //set bit1, period mode
  TIMER3_CONTROLREG &= ~(1<<2); //clear bit2, unmask interrupt means enable
  TIMER3_LOADCOUNT = TIMEOUT_PERIOD;
  TIMER3_CONTROLREG |= 1<<0; //set bit0, enable timer

  //enable timer3 interrupt
  //timer3 irqnum = systimer irqnum = 7, enable in vectors.s

  //set timer3 irq_priority 
  unsigned int csr_be0;  //int_prio

  __asm__ __volatile__("csrr %0, 0xbe0":"=r"(csr_be0));
  csr_be0 &= ~(0x0f<<8); //clear bit8-11
  csr_be0 |= 0x4<<8; //set bit8-11 prio to 4
  __asm__ __volatile__("csrw 0xbe0, %0":"=r"(csr_be0));  
}

void disableGlobalInt(void) {
  __asm__ __volatile__("csrci  mstatus,0x08");  
}

void enableGlobalInt(void) {
  __asm__ __volatile__("csrsi  mstatus,0x08");  
}


/**
 * for .s debug
 */
void showMsg(unsigned int i, unsigned int data) {
  if (i==0) {
    printf("enter isrWrapper\n");
  }else if (i==1) {
    printf("mcause:0x%x\n", data);
  }else {
    printf("i=%d: data=0x%x\n", i, data);
  }
}
